/*
 * @Descripttion: 群发消息接口
 * @version: 1.0
 * @Author: 自由如风
 * @Date: 2021-05-24 10:34:59
 * @LastEditors: 自由如风
 * @LastEditTime: 2021-05-28 14:20:03
 */
import { WX } from '../index'

import _axios from 'axios';
import { AxiosInstance } from 'axios';
import { create_axios } from '../tool/WXAxios'
/** 群发消息接口 */
export class Mass {
    private readonly SEND = 'https://api.weixin.qq.com/cgi-bin/message/mass/send';
    private readonly SENDAll = 'https://api.weixin.qq.com/cgi-bin/message/mass/sendall';
    private readonly UPLOADVIDEO = 'https://api.weixin.qq.com/cgi-bin/media/uploadvideo'
    private readonly DELETE = 'https://api.weixin.qq.com/cgi-bin/message/mass/delete'
    private readonly PREVIEW = 'https://api.weixin.qq.com/cgi-bin/message/mass/preview'
    private readonly GETSTATUS = 'https://api.weixin.qq.com/cgi-bin/message/mass/get'
    private readonly GETSPEED = 'https://api.weixin.qq.com/cgi-bin/message/mass/speed/get'
    private readonly SETSPEED = 'https://api.weixin.qq.com/cgi-bin/message/mass/speed/set'

    private app: WX;
    private axios: AxiosInstance;


    constructor(app: WX) {
        this.app = app;
        /** 创建一个自己的axios实例 */
        this.axios = create_axios(app);
    }

    public send(params: { msgtype: 'mpnews' | 'text' | 'voice' | 'image' | 'mpvideo' | 'wxcard' }): Promise<{
        /** 媒体文件类型，分别有图片（image）、语音（voice）、视频（video）和缩略图（thumb），图文消息为news */
        type: string,
        /** 错误码 */
        errcode: number,
        /** 错误信息 */
        errmsg: string,
        /** 消息发送任务的ID */
        msg_id: number,
        /** 消息的数据ID，该字段只有在群发图文消息时，才会出现。可以用于在图文分析数据接口中，获取到对应的图文消息的数据，是图文分析数据接口中的msgid字段中的前半部分，详见图文分析数据接口中的msgid字段的介绍。 */
        msg_data_id: number
    }> {
        return this.axios.post(this.SEND, params)
    }

    public sendAll(params: { msgtype: 'mpnews' | 'text' | 'voice' | 'image' | 'mpvideo' | 'wxcard' }): Promise<{
        errcode: number,
        errmsg: string,
        msg_id: number,
        msg_data_id: number
    }> {
        return this.axios.post(this.SENDAll, params)
    }

    /** 通过 openId 发送图文 */
    public sendNewsByOpenId(params: {
        /** 填写图文消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        /** 用于设定即将发送的图文消息 */
        mpnews: {
            /** 用于群发的图文消息的media_id */
            media_id: string
        }
        /** 图文消息被判定为转载时，是否继续群发。 1为继续群发（转载），0为停止群发。 该参数默认为0。 */
        send_ignore_reprint: 0 | 1
    }) {
        return this.send({ ...params, msgtype: 'mpnews' })
    }

    /** 通过 openId 群发文本 */
    public sendTextByOpenId(params: {
        /** 填写文本消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        text: {
            /** 要群发的文本消息 */
            content: string
        }
    }) {
        return this.send({ ...params, msgtype: 'text' })
    }



    /** 通过 openId 群发语音/音频 */
    public sendVoice(params: {
        /** 填写语音/音频消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        voice: {
            /** 通过素材管理->新增素材来得到媒体ID */
            media_id: string,
        }
    }) {
        return this.send({ ...params, msgtype: 'voice' })
    }

    /** 通过 opendId 群发图片 */
    public sendImageByOpenId(params: {
        /** 填写图文消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        images: {
            media_ids: string[],
            /** 推荐语，不填则默认为“分享图片” */
            recommend: string,
            /** Uint32 是否打开评论，0不打开，1打开 */
            need_open_comment: 0 | 1,
            /** Uint32 是否粉丝才可评论，0所有人可评论，1粉丝才可评论 */
            only_fans_can_comment: 0 | 1
        }
    }) {
        return this.send({ ...params, msgtype: 'image' })
    }

    /** 
     * 通过 openId 群发视频 注意此处media_id需通过uploadvideo方法得到
     *  */
    public sendVideoByOpenId(params: {
        /** 填写视频消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        mpvideo: {
            media_id: string,
            /** 消息的标题 */
            title: string,
            /** 消息的描述 */
            description: string
        }
    }) {
        return this.send({ ...params, msgtype: 'mpvideo' })
    }

    /** 通过 openid 群发卡券 */
    public sendWxcardByOpenId(params: {
        /** 填写卡券消息的接收者，一串OpenID列表，OpenID最少2个，最多10000个 */
        touser: string[],
        wxcard: { card_id: string }
    }) {
        return this.send({ ...params, msgtype: 'wxcard' })
    }


    // ========================= 通过 标签进行群发 ===========================

    /** 通过 tag 发送图文消息 */
    public sendNewsByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        mpnews: {
            /** 用于群发的消息的media_id */
            media_id: string,
        },

        send_ignore_reprint: 0 | 1
    }) {
        return this.sendAll({ ...params, msgtype: "mpnews" });
    }

    /** 通过 tag 发送文本消息 */
    public sendTextByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        text: {
            /** 文本的内容 */
            content: string
        },
    }) {
        return this.sendAll({ ...params, msgtype: "text" });
    }

    /** 通过 tag 发送语音/音频消息 （注意此处media_id需通过素材管理->新增素材来得到） */
    public sendVoiceByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        voice: {
            /** 用于群发的消息的media_id */
            media_id: string
        },
    }) {
        return this.sendAll({ ...params, msgtype: "voice" });
    }

    /** 通过 tag 发送图片（注意此处media_id需通过素材管理->新增素材来得到） */
    public sendImageByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        images: {
            /** 用于群发的消息的media_id */
            media_ids: string[],
            /** 推荐语，不填则默认为“分享图片” */
            recommend: string,
            /** Uint32 是否打开评论，0不打开，1打开 */
            need_open_comment: 1,
            /** Uint32 是否粉丝才可评论，0所有人可评论，1粉丝才可评论 */
            only_fans_can_comment: 0
        },
    }) {
        return this.sendAll({ ...params, msgtype: "image" });
    }

    /**
     * 通过 tag 发送视频（注意此处media_id需通过uploadvideo方法得到）
     */
    public sendVideoByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        mpvideo: {
            /** 用于群发的消息的media_id */
            media_id: string
        },
    }) {
        return this.sendAll({ ...params, msgtype: "mpvideo" });
    }

    /** 卡券消息（注意图文消息的media_id需要通过上述方法来得到） */
    public sendWXcardByTag(params: {
        filter: {
            /** 用于设定是否向全部用户发送，值为true或false，选择true该消息群发给所有用户，选择false可根据tag_id发送给指定群组的用户 */
            is_to_all: boolean,
            /** 群发到的标签的tag_id，参见用户管理中用户分组接口，若is_to_all值为true，可不填写tag_id */
            tag_id: number
        },
        wxcard: {
            card_id: string
        },
    }) {
        return this.sendAll({ ...params, msgtype: "wxcard" });
    }


    // ============   特别接口  ===================

    /** 将素材管理的 media_id 转换成 群发视频的 media_id */
    public uploadvideo(params: {
        /** 此处media_id需通过素材管理->新增素材来得到 */
        media_id: string,
        /** 消息的标题 */
        title: string,
        /** 消息的描述 */
        description: string
    }): Promise<{
        /** 固定等于 video */
        type: "video",
        /** 可用于发送视频的媒体ID */
        media_id: string,
        created_at: number
    }> {
        return this.axios.post(this.UPLOADVIDEO, params)
    }

    /** 删除群发【订阅号与服务号认证后均可用】 */
    public delete(params: {
        /** 发送出去的消息ID */
        msg_id: number,
        /** 要删除的文章在图文消息中的位置，第一篇编号为1，该字段不填或填0会删除全部文章 */
        article_idx: number
    }): Promise<{
        errcode: number,
        errmsg: string
    }> {
        return this.axios.post(this.DELETE, params)
    }

    /** 预览接口【订阅号与服务号认证后均可用】 */
    public preview(params: any): Promise<{
        /** 错误码 */
        errcode: number,
        /** 错误信息 */
        errmsg: string,
        /** 消息ID */
        msg_id: number
    }> {
        return this.axios.post(this.PREVIEW, params)
    }

    /** 查询群发消息发送状态【订阅号与服务号认证后均可用】 */
    public getStatus(params: {
        /** 群发消息后返回的消息id */
        msg_id: number,
    }): Promise<{
        /** 群发消息后返回的消息id */
        errcode: number,
        /** 消息发送后的状态，SEND_SUCCESS表示发送成功，SENDING表示发送中，SEND_FAIL表示发送失败，DELETE表示已删除 */
        errmsg: string
    }> {
        return this.axios.post(this.GETSTATUS, params)
    }

    /** 获取群发速度 */
    public getSpeed(): Promise<{
        /** 群发速度的级别 */
        speed: number,
        /** 群发速度的真实值 单位：万/分钟 */
        realspeed: number
    }> {
        return this.axios.get(this.GETSPEED)
    }

    /** 设置群发速度 0=80w/分钟 1=60w/分钟 2=45w/分钟 3=30w/分钟 4=10w/分钟 */
    public setSpeed(params: {
        /** 群发速度的级别，是一个0到4的整数，数字越大表示群发速度越慢。 */
        speed: number,
    }): Promise<{
        errcode: number,
        errmsg: string
    }> {
        return this.axios.post(this.SETSPEED, params)
    }
}